package showtime.framework.manager
{
	import showtime.framework.core.pattern.Singleton;
	import showtime.framework.events.SocketEvent;
	import showtime.framework.net.tcp.BaseSocket;
	import showtime.struct.ArrayCollection;
	
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.getClassByAlias;
	import flash.net.registerClassAlias;
	
	/** 
	 * @project showtime
	 * @author yinhao
	 * @date 2010-12-26
	 *
	 */
	
	public class SocketManager extends Singleton
	{
		private var connectionMap:Object = null;
				
		private var currentConnectAmount:uint = 0;
		
		public var connectAmount:uint = 0;
		
		public var asyncWaitingFor:Function = null;
		
		public function SocketManager()
		{
			super();
			
			initialize();
		}
		
		static public function getInstance():SocketManager
		{
			return SocketManager(Singleton.getInstanceOrCreate(SocketManager));
			
		}
		
		/**
		 * Build socket connection. 
		 * 
		 */		
		public function buildConnection(name:String, host:String, port:uint, heartBeatCheck:Boolean = false, keepAliveTimeout:int = 10000, checkInterval:int = 10000):BaseSocket
		{
			var socket:BaseSocket = new BaseSocket();
			
			socket.addEventListener(SocketEvent.CONNECT, connectHandler);
	
			socket.addEventListener(SocketEvent.IO_ERROR, ioErrorHandler);
			
			socket.addEventListener(SocketEvent.HEART_BEAT_ERROR, heartBeatErrorHandler);
			
			connectionMap[name] = socket;

			socket.connect(host, port, heartBeatCheck, keepAliveTimeout, checkInterval);
			
			return socket;
		}
		
		/**
		 * Get socket connection instance. 
		 * @param name
		 * @return 
		 * 
		 */		
		public function getConnection(name:String):BaseSocket
		{
			return BaseSocket(connectionMap[name]);
		}
		
		/**
		 * Pre initialize. 
		 * 
		 */		
		override protected function initialize():void
		{
			super.initialize();
			
			try
			{
				if (getClassByAlias("flex.messaging.io.ArrayCollection") == null)
				{
					registerClassAlias("flex.messaging.io.ArrayCollection", ArrayCollection);				
				}
			}
			catch(e:ReferenceError)
			{
				registerClassAlias("flex.messaging.io.ArrayCollection", ArrayCollection);		
			}
			
			connectionMap = {};
						
		}
		
		public function loadFromXML(path:String):void
		{
			var urlLoader:URLLoader = new URLLoader();
			
			urlLoader.load(new URLRequest(path));
			
			urlLoader.addEventListener(Event.COMPLETE, loadCompleteHandler);
			
			function loadCompleteHandler(event:Event):void
			{
				urlLoader.removeEventListener(Event.COMPLETE, loadCompleteHandler);
				// Analysis xml data.
				xmlAnalysis(new XML(urlLoader.data));
			}
		}
		
		private function xmlAnalysis(xml:XML):void
		{
			for each (var element:XML in xml.socketConfig.socket)
			{
				var name:String = element.@name;
				var host:String = element.@host;
				var port:String = element.@port;				
				
				buildConnection(name, host, uint(port));
				
				connectAmount++;
			}
		}
		
		/**
		 * All connection build will case this action happen. 
		 * @param event
		 * 
		 */		
		private function connectHandler(evt:Event):void
		{
			currentConnectAmount++;
				
			if (connectAmount == currentConnectAmount && asyncWaitingFor != null)
			{
				trace("[Socket Manager] - net connection build complete.");	
				asyncWaitingFor.call();
			};
		}
		
		private function ioErrorHandler(evt:Event):void
		{
			trace("[Socket Manager] - net connection build failed.");	
		}
		
		private function heartBeatErrorHandler(evt:Event):void
		{
			trace("[Socket Manager] - heart beat error.");
		}
		
		/**
		 * Judge socket is connected. 
		 * @param name
		 * @return 
		 * 
		 */		
		public function connected(name:String):Boolean
		{
			return getConnection(name).connected();
		}
	}
}